package top.cyuw.subjectsystem.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.cyuw.subjectsystem.dto.PagingParamDto;
import top.cyuw.subjectsystem.dto.subject.SubjectCreateRequest;
import top.cyuw.subjectsystem.dto.subject.SubjectEditRequest;
import top.cyuw.subjectsystem.entity.Selection;
import top.cyuw.subjectsystem.entity.Subject;
import top.cyuw.subjectsystem.mapper.SubjectMapper;
import top.cyuw.subjectsystem.service.SelectionService;
import top.cyuw.subjectsystem.service.SubjectService;
import top.cyuw.subjectsystem.util.MapperUtils;
import top.cyuw.subjectsystem.vo.PagingVo;
import top.cyuw.subjectsystem.vo.subject.SubjectVo;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SubjectServiceImpl extends ServiceImpl<SubjectMapper, Subject> implements SubjectService {

    @Autowired
    SelectionService selectionService;

    @Override
    public SubjectVo getById(Integer id) {
        return MapperUtils.map(getByIdInternal(id), SubjectVo.class);
    }

    private Subject getByIdInternal(Integer id) {
        LambdaQueryWrapper<Subject> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Subject::getId, id);
        return super.getOne(wrapper, false);
    }

    @Override
    public Boolean create(SubjectCreateRequest request) {
        Subject subject = new Subject();
        subject.setName(request.getName());
        subject.setDescription(request.getDescription());
        Date now = new Date();
        subject.setUpdateTime(now);
        subject.setCreateTime(now);
        return super.save(subject);
    }

    @Override
    public Boolean delete(Integer id) {
        return super.removeById(id);
    }

    @Override
    public Boolean edit(SubjectEditRequest request) {
        Subject subject = getByIdInternal(request.getId());
        if (StringUtils.isNotEmpty(request.getName())) {
            subject.setName(request.getName());
        }
        if (StringUtils.isNotEmpty(request.getDescription())) {
            subject.setDescription(request.getDescription());
        }
        subject.setLimits(request.getLimits());
        subject.setUpdateTime(new Date());
        return super.updateById(subject);
    }

    @Override
    public PagingVo<SubjectVo> search(PagingParamDto<String> request) {
        LambdaQueryWrapper<Subject> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(Subject::getName, request.getParam());
        Page<Subject> page = super.page(
                new Page<>(request.getPageNum(), request.getPageSize()), wrapper);
        return PagingVo.of(MapperUtils.mapList(page.getRecords(), SubjectVo.class),
                page.getTotal(), page.getCurrent(), page.getPages());
    }

    @Override
    public Map<String, Object> echart() {
        List<Subject> subjects = super.list();
        List<Selection> selections = selectionService.list();

        Map<String, Object> result = new HashMap<>(2);

        Map<Subject, Integer> counter = new LinkedHashMap<>();
        for (Selection selection : selections) {
            Subject subject = getSelection(subjects, selection.getSubjectId());
            if (subject != null) {
                int count = counter.getOrDefault(subject, 0) + 1;
                counter.put(subject, count);
            }
        }

        result.put("xAxis", counter.keySet().stream().map(Subject::getName).collect(Collectors.toList()));
        result.put("yAxis", counter.values().toArray(new Integer[0]));
        return result;
    }

    private Subject getSelection(List<Subject> subjects, Integer subjectId) {
        for (Subject subject : subjects) {
            if (subject.getId().equals(subjectId)) {
                return subject;
            }
        }
        return null;
    }

}
